package tech.konata.yukkuri;

import joptsimple.OptionParser;
import joptsimple.OptionSet;
import lombok.Getter;
import lombok.SneakyThrows;
import tech.konata.yukkuri.gui.YukkuriGui;
import tech.konata.yukkuri.utils.HttpUtils;

import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Scanner;

public class Yukkuri {

    @Getter
    private static final Yukkuri instance = new Yukkuri();

    public Yukkuri() {

    }

    final Scanner scanner = new Scanner(System.in).useDelimiter("\n");

    final File outputDir = new File("Yukkuri");

    @SneakyThrows
    public void run(String[] args) {

        // Change encoding

        System.setProperty("file.encoding", "GBK");

        System.out.println("Credit: BiliBili @ IzumiiKonata");

        OptionParser optionparser = new OptionParser();
        optionparser.allowsUnrecognizedOptions();

        optionparser.accepts("cli");

        OptionSet optionset = optionparser.parse(args);

        boolean bCli = optionset.has("cli");

        if (!this.outputDir.exists()) {
            boolean bResult = this.outputDir.mkdir();

            if (!bResult) {
                System.err.println("无法创建文件夹!");
                System.exit(1);
            }
        }

        if (!this.outputDir.isDirectory()) {
            boolean bResult = this.outputDir.delete();

            if (!bResult) {
                System.err.println("无法重新创建文件夹!");
                System.exit(1);
            }

            bResult = this.outputDir.mkdir();

            if (!bResult) {
                System.err.println("无法创建文件夹!");
                System.exit(1);
            }
        }

        if (bCli) {
            // command line mode
            this.launchCli();
        } else {

            // launch gui
            new YukkuriGui().showGui();

        }

    }

    public void launchCli() {
        System.out.print("请输入待转换的文字: ");

        while (scanner.hasNext()) {

            String input = scanner.nextLine();

            String katakana = this.convertToKatakana(input);
            System.out.println("片假名转换: " + katakana);

            if (katakana.length() > 140) {
                System.out.println("[!] 转换后的长度超过140个字符 请减少文字量");
                continue;
            }

            this.generateAndSave(katakana, input);

            System.out.print("请输入待转换的文字: ");

        }
    }

    @SneakyThrows
    public String convertToKatakana(String input) {

        HashMap<String, String> params = new HashMap<>();

        params.put("contents", URLEncoder.encode(input, "UTF-8"));
        params.put("firstInput", "OK");
        params.put("option", "1");
        params.put("optionext", "zenkaku");

        String post = HttpUtils.postString("https://www.ltool.net/chinese-simplified-and-traditional-characters-pinyin-to-katakana-converter-in-simplified-chinese.php", params);

        // 暴力解析html :)

        post = post.substring(post.indexOf("<div class='finalresult'>") + "<div class='finalresult'>".length());
        post = post.substring(0, post.indexOf("</div></form><div style=clear:both></div>")).replaceAll(" ", "");

        while (post.contains("<spanstyle=color:#aaaaaa>")) {
            post = post.replace(post.substring(post.indexOf("<spanstyle=color:#aaaaaa>"), post.indexOf("</span>") + "</span>".length()), "");
        }

        post = post.replaceAll("</div>", "");

        return post;

    }

    @SneakyThrows
    public void generateAndSave(String katakana, String fileName) {

        HashMap<String, String> params2 = new HashMap<>();

        params2.put("type", "f1");
        params2.put("kanji", URLEncoder.encode(katakana, "UTF-8"));

        // 访问油库里api
        InputStream is = HttpUtils.get("https://www.yukumo.net/api/v2/aqtk1/koe.mp3", params2);

        File dest = new File(this.outputDir, fileName + ".mp3");

        byte[] bytes = this.readAllBytes(is);

        FileOutputStream fos = new FileOutputStream(dest);

        fos.write(bytes);
        fos.close();

        System.out.println("OK! 已保存至Yukkuri\\" + fileName + ".mp3");
    }

    @SneakyThrows
    public void generateAndSavePro(String katakana, String fileName, YukkuriGui.VoiceType type, boolean echo, boolean boyomi, int speed, int volume) {

        HashMap<String, String> params2 = new HashMap<>();

        params2.put("type", type.getType());

        if (echo) {
            params2.put("effect", "echo");
        } else {
            params2.put("effect", "none");
        }

        params2.put("boyomi", String.valueOf(boyomi));
        params2.put("speed", String.valueOf(speed));
        params2.put("volume", String.valueOf(volume));

        if (type.isExtraParameters()) {
            params2.put("pitch", String.valueOf(type.getPitch()));
            params2.put("accent", String.valueOf(type.getAccent()));
            params2.put("lmd", String.valueOf(type.getLmd()));
            params2.put("fsc", String.valueOf(type.getFsc()));
        }

        params2.put("kanji", URLEncoder.encode(katakana, "UTF-8"));

        String typeApi = "";

        if (type.name().startsWith("AT1"))
            typeApi = "k1";
        if (type.name().startsWith("AT2"))
            typeApi = "k2";
        if (type.name().startsWith("AT10"))
            typeApi = "k10";

        // 访问油库里api
        InputStream is = HttpUtils.get("https://www.yukumo.net/api/v2/aqt" + typeApi + "/koe.mp3", params2);

        File dest = new File(this.outputDir, fileName + ".mp3");

        byte[] bytes = this.readAllBytes(is);

        FileOutputStream fos = new FileOutputStream(dest);

        fos.write(bytes);
        fos.close();

        System.out.println("OK! 已保存至Yukkuri\\" + fileName + ".mp3");
    }

    private byte[] readAllBytes(InputStream inputStream) throws IOException {
        final int bufLen = 4 * 0x400; // 4KB
        byte[] buf = new byte[bufLen];
        int readLen;
        IOException exception = null;

        try {
            try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
                while ((readLen = inputStream.read(buf, 0, bufLen)) != -1)
                    outputStream.write(buf, 0, readLen);

                return outputStream.toByteArray();
            }
        } catch (IOException e) {
            exception = e;
            throw e;
        } finally {
            if (exception == null) inputStream.close();
            else try {
                inputStream.close();
            } catch (IOException e) {
                exception.addSuppressed(e);
            }
        }
    }

}
